<template>
  <!-- <div id="container">
  </div> -->
</template>

<script setup>
import * as THREE from 'three'
// 引入轨道控制器扩展库OrbitControls.js
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// 引入dat.gui.js的一个类GUI
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
// 引入gltf模型加载库GLTFLoader.js
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';

// 创建GLTF加载器对象
const loader = new GLTFLoader();

// 实例化一个gui对象
const gui = new GUI();
//改变交互界面style属性
gui.domElement.style.right = '0px';
gui.domElement.style.width = '300px';

// 创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);


const scene = new THREE.Scene()

// 添加一个辅助网格地面
const gridHelper = new THREE.GridHelper(10, 10, 0x004444, 0x004444);
scene.add(gridHelper)

// AxesHelper：辅助观察的坐标系
const axesHelper = new THREE.AxesHelper(20);
scene.add(axesHelper);
// 实例化一个透视投影相机对象
// 30:视场角度, width / height:Canvas画布宽高比, 1:近裁截面, 3000：远裁截面
// // 超出视锥体远裁界面的范围的会被剪裁掉，不渲染  可以调整far参数适配 所以要看全部就把远裁面拉高10000
const camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 1, 10000);


// 创建光源
const light = new THREE.AmbientLight(0xffffff);
scene.add(light);
//相机在Three.js三维坐标系中的位置
// 根据需要设置相机位置具体值
camera.position.set(16, 100, 16);
// camera.lookAt(mesh.position);//指向mesh对应的位置
// // 改变相机观察目标点
camera.lookAt(10, 0, 0);
// 设置相机控件轨道控制器OrbitControls
// 创建渲染器对象
// 设置渲染器锯齿属性.antialias的值可以直接在参数中设置，也可通过渲染器对象属性设置
//环境光:没有特定方向，整体改变场景的光照明暗
const ambient = new THREE.AmbientLight(0xffffff, 0.4);
scene.add(ambient);



// 不同硬件设备的屏幕的设备像素比window.devicePixelRatio值可能不同
console.log('查看当前屏幕设备像素比', window.devicePixelRatio);
// 或者直接设置参数  renderer.antialias = true

loader.load(`static/fourbox1.glb`, function (gltf) {
  console.log('控制台查看加载gltf文件返回的对象结构', gltf);
  console.log('gltf对象场景属性', gltf.scene);
  // 给加载的模型设置位置和旋转
  // gltf.scene.position.set(0, 0, 0);
  // gltf.scene.rotation.set(0, 0, 0);
  // 返回的场景对象gltf.scene插入到threejs场景中

  // 返回名.name为"1号楼"对应的对象
  const nameNode = gltf.scene.getObjectByName("first");
  nameNode.material.color.set(0xff0000);//改变1号楼Mesh材质颜色
  nameNode.material.name = 'color'
  const nameNode1 = gltf.scene.getObjectByName("second");
  console.log(nameNode1.material.name) // color

  // 材质共享问题
  // 解决问题方向

  // 改变一个模型颜色其它模型跟着变化，是因为多个模型对象共享了材质，如果单独改变一个模型的材质，比如颜色，下面两个方案，可以任选其一。

  // 三维建模软件中设置，需要代码改变材质的Mesh不要共享材质，要独享材质。
  // 代码批量更改：克隆材质对象，重新赋值给mesh的材质属性

  // 代码方式解决多个mesh共享材质的问题

  // //用代码方式解决mesh共享材质问题
  // gltf.scene.getObjectByName("小区房子").traverse(function (obj) {
  //   if (obj.isMesh) {
  //     // .material.clone()返回一个新材质对象，和原来一样，重新赋值给.material属性
  //     obj.material = obj.material.clone();
  //   }
  // });
  // mesh1.material.color.set(0xffff00);
  // mesh2.material.color.set(0x00ff00);



  // 递归遍历model包含所有的模型节点
  gltf.scene.traverse(function (obj) {
    console.log('所有模型节点的名称', obj.name, obj.isMesh);
    // obj.isMesh：if判断模型对象obj是不是网格模型'Mesh'
    if (obj.isMesh) {//判断条件也可以是obj.type === 'Mesh'
      // 重新设置材质
      obj.material = new THREE.MeshLambertMaterial({
        color: 0xffffff,
      });
    }
  });
  scene.add(gltf.scene);
})

function render() {
  // console.log('camera', camera.position)
  renderer.render(scene, camera); //执行渲染操作
  requestAnimationFrame(render);//请求再次执行渲染函数render，渲染下一帧
}
render();

const controls = new OrbitControls(camera, renderer.domElement);
// 相机控件.target属性在OrbitControls.js内部表示相机目标观察点，默认0,0,0
// console.log('controls.target', controls.target);
controls.target.set(10, 0, 0);
controls.update();//update()函数内会执行camera.lookAt(controls.targe)


// 如果OrbitControls改变了相机参数，重新调用渲染器渲染三维场景
controls.addEventListener('change', function () {
  // 浏览器控制台查看相机位置变化
  // console.log('camera.position', camera.position);
  // 渲染循环和相机控件OrbitControls

  // 设置了渲染循环, 相机控件OrbitControls就不用再通过事件change执行renderer.render(scene, camera);，毕竟渲染循环一直在执行renderer.render(scene, camera);。
  // renderer.render(scene, camera); //执行渲染操作
});//监听鼠标、键盘事件

</script>
<style scoped>
#container {
  width: 500px;
  height: 500px;
  margin: 100px auto;
  background: gray;
}
</style>